#include <include/core/SkCanvas.h>
#include <skia_framework.h>
#include <txt/paragraph_builder.h>

#define T1 "你好世界1"
#define T2 "Hello World2"
#define T3 "שלום, עולם.3"
#define T4 " مرحبا العالم . 4"
#define T5 "こんにちは、世界。5"

struct ParagraphData {
    std::string title;
    std::u16string u16text;
    txt::ParagraphStyle ps = {};
    txt::TextStyle ts = { .color = SK_ColorBLACK };
} datas[] = {
    {
        .title = "1 12345",
        .u16text = u"" T1 T2 T3 T4 T5,
    },
    {
        .title = "1r 12345",
        .u16text = u"" T1 T2 T3 T4 T5,
        .ps = { .text_direction = txt::TextDirection::rtl },
    },
    {
        .title = "2 34125",
        .u16text = u"" T3 T4 T1 T2 T5,
        .ps = { .text_direction = txt::TextDirection::rtl },
    },
    {
        .title = "2l 34125",
        .u16text = u"" T3 T4 T1 T2 T5,
    },
    {
        .title = "3 54321",
        .u16text = u"" T5 T4 T3 T2 T1,
    },
    {
        .title = "3r 54321",
        .u16text = u"" T5 T4 T3 T2 T1,
        .ps = { .text_direction = txt::TextDirection::rtl },
    },
    {
        .title = "4 43215",
        .u16text = u"" T4 T3 T2 T1 T5,
        .ps = { .text_direction = txt::TextDirection::rtl },
    },
    {
        .title = "4l 43215",
        .u16text = u"" T4 T3 T2 T1 T5,
    },
    {
        .title = "5",
        .u16text = u"" T3 T4,
        .ps = { .text_direction = txt::TextDirection::rtl },
    },
    {
        .title = "5l",
        .u16text = u"" T3 T4,
    },
};

struct DrawingData {
    std::string title;
    std::unique_ptr<txt::Paragraph> paragraph;
};

int main()
{
    auto collection = std::make_shared<txt::FontCollection>();
    collection->SetupDefaultFontManager();
    auto dfmanager = sk_make_sp<txt::DynamicFontManager>();
    collection->SetDynamicFontManager(dfmanager);

    std::vector<struct DrawingData> drawingDatas;
    for (const auto &[title, u16text, ps, ts] : datas) {
        auto builder = txt::ParagraphBuilder::CreateTxtBuilder(ps, collection);
        builder->PushStyle(ts);
        builder->AddText(u16text);
        auto paragraph = builder->Build();
        paragraph->Layout(200);
        drawingDatas.push_back({
            .title = title,
            .paragraph = std::move(paragraph),
        });
    }

    SkiaFramework sf;
    sf.SetDrawFunc([&](SkCanvas &canvas) {
        canvas.save();
        canvas.translate(100, 100);

        double offsetX = 0;
        double offsetY = 0;
        double maxWidth = 0;
        for (const auto &[title, paragraph] : drawingDatas) {
            if (offsetY + paragraph->GetHeight() >= 1000) {
                offsetX += maxWidth + 50;
                offsetY = 0;
                maxWidth = 0;
            }

            SkPaint bgpaint;
            bgpaint.setColor(0xffcccccc);
            bgpaint.setStyle(bgpaint.kStrokeAndFill_Style);
            canvas.drawRect(SkRect::MakeXYWH(offsetX, offsetY, paragraph->GetMaxWidth(), paragraph->GetHeight()), bgpaint);
            sf.DrawString(canvas, title, offsetX, offsetY);

            constexpr SkColor colors[] = {SK_ColorRED, SK_ColorYELLOW, SK_ColorGREEN, SK_ColorBLUE};
            canvas.save();
            canvas.translate(offsetX, offsetY);
            std::vector<txt::Paragraph::TextBox> boxes;
            for (int32_t i = 0; ; i++) {
                constexpr auto heightStyle = txt::Paragraph::RectHeightStyle::kTight;
                constexpr auto widthStyle = txt::Paragraph::RectWidthStyle::kTight;
                auto box = paragraph->GetRectsForRange(i, i + 1, heightStyle, widthStyle);
                if (box.empty()) {
                    break;
                }

                boxes.insert(boxes.end(), box.begin(), box.end());
            }

            int32_t index = 0;
            for (const auto &box : boxes) {
                SkPaint paint;
                paint.setColor(colors[index / 5 % (sizeof(colors) / sizeof(colors[0]))]);
                paint.setAlpha(255.0 / 5 * (5 - index % 5));
                index++;
                canvas.drawRect(box.rect, paint);
            }
            canvas.restore();

            paragraph->Paint(&canvas, offsetX, offsetY);
            offsetY += paragraph->GetHeight() + 50;
            maxWidth = std::max(maxWidth, paragraph->GetMaxWidth());
        }

        canvas.restore();
    });
    sf.Run();

    return 0;
}
